using ACS.Compiler.Tables;
using ACS.Compiler.Tables.Modes;
using ACS.Compiler.Tree.Impl;
using ACS.Compiler.Util;
using antlr;
using antlr.collections;
using ACS.Compiler.Tree.Interfaces;

namespace ACS.Compiler.Tree
{
    public class TreeBase : BaseAST
    {
        private string _tokenName;

        private IToken _token;

        public IToken Token
        {
            get { return _token; }
        }

        private TreeTags _tag = TreeTags.NoTag;

        public override void initialize(int t, string txt)
        {
            _tokenName = txt; 
        }

        public override void initialize(AST t)
        {
        }

        public override void initialize(IToken t)
        {
            _tokenName = t.getText();
            _token = t;
        }

        public virtual void Build()
        {
            TreeBase child = (TreeBase)getFirstChild(); 
            while(child != null)
            {
                child.Build();
                MatchChild(child);
                child = (TreeBase)child.getNextSibling(); 
            }
            AllFieldsParsed();
        }

        public virtual void AllFieldsParsed()
        {
            
        }

        public virtual void MatchChild(TreeBase child)
        {
            switch (child.Tag)
            {
                case TreeTags.Module:
                    MatchModule((Module) child);
                    break;
                case TreeTags.Type:
                    MatchType((TypeDef) child);
                    break;
                case TreeTags.TypeDeclarer:
                    MatchTypeDeclarer((TypeDeclarer) child);
                    break;
                case TreeTags.Data:
                    MatchData((Data) child);
                    break;
                case TreeTags.TypeField:
                    MatchTypeField((TypeField) child);
                    break;
                case TreeTags.Ident:
                    MatchIdent((Ident) child);
                    break;
                case TreeTags.Proc:
                    MatchProc((Proc) child);
                    break;
                case TreeTags.FormalParameter:
                    MatchFormalParameter((FormalParameter) child);
                    break;
                case TreeTags.Block:
                    MatchBlock((Block) child);
                    break;
                case TreeTags.Assign:
                case TreeTags.Return:
                case TreeTags.If:
                case TreeTags.While:
                    MatchStatement((Statement)child);
                    break;
                case TreeTags.Arrow:
                case TreeTags.BoolConst:
                case TreeTags.IntConst:
                case TreeTags.Plus:
                case TreeTags.Slice:
                case TreeTags.Star:
                case TreeTags.Eqq:
                case TreeTags.StringConst:
                    MatchExpression((IExpression)child);
                    break;
                case TreeTags.Select:
                    MatchSelect((Select) child);
                    break;
                case TreeTags.Call:
                    MatchCall((Call) child);
                    break;
                case TreeTags.CallParameter:
                    MatchCallParameter((CallParameter) child);
                    break;
                default:
                    break;
            } 
        }

        public virtual void MatchCallParameter(CallParameter call)
        {
            Logger.Instance.TraceError("Unexpected match1");
        }

        public virtual void MatchSelect(Select select)
        {
            Logger.Instance.TraceError("Unexpected match2");
        }

        public virtual void MatchExpression(IExpression expression)
        {
            Logger.Instance.TraceError("Unexpected match3");
        }

        public virtual void MatchCall(Call call)
        {
            Logger.Instance.TraceError("Unexpected match4");
        }

        public virtual void  MatchStatement(Statement statement)
        {
            Logger.Instance.TraceError("Unexpected match5");
        }

        public virtual void  MatchBlock(Block block)
        {
            Logger.Instance.TraceError("Unexpected match6");
        }

        public virtual void MatchFormalParameter(FormalParameter parameter)
        {
            Logger.Instance.TraceError("Unexpected match7");
        }

        public virtual void MatchProc(Proc proc)
        {
            Logger.Instance.TraceError("Unexpected match8");
        }

        public virtual void MatchIdent(Ident ident)
        {
            Logger.Instance.TraceError("Unexpected match9");
        }

        public virtual void MatchTypeField(TypeField field)
        {
            Logger.Instance.TraceError("Unexpected match10");
        }

        public virtual void MatchTypeDeclarer(TypeDeclarer declarer)
        {
            Logger.Instance.TraceError("Unexpected match11");
        }

        public virtual void  MatchData(Data data)
        {
            Logger.Instance.TraceError("Unexpected match12");
        }

        public virtual void MatchType(TypeDef def)
        {
            Logger.Instance.TraceError("Unexpected match13");
        }

        public virtual void MatchModule(Module module)
        {
            Logger.Instance.TraceError("Unexpected match14");
        }


        public override string ToString()
        {
            return _tokenName??""; 
        }

        public virtual TreeTags Tag
        {
            get
            {
                return _tag;
            }
        }


        public IToken FindToken()
        {
            if (Token == null)
            {
                TreeBase child = (TreeBase)getFirstChild();
                while (child != null)
                {
                    IToken ret = child.FindToken();
                    if (ret != null)
                    {
                        return ret;
                    }
                    child = (TreeBase)child.getNextSibling();
                }
            }
            else
            {
                return Token;
            }
            return null;
        }


    }
}
